using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using OpenComposite.Base.Designer;
using OpenComposite.EII.Designer.Generic;
using OpenComposite.Repository.Properties;
using OpenComposite.EII.Repository;
using WeifenLuo.WinFormsUI.Docking;

namespace OpenComposite.EII.Designer.SCA
{
	public class InterfaceSymbol : Symbol, IConnectorFactory, IRepositoryItemSymbol
	{
		#region Initialization
		public InterfaceSymbol()
		{
			init();
		}
		private void init()
		{
			this.BeginUpdate();

			//_connectorInterface = null;

			this.Border = BorderType.CustomPolygon; //BorderType.SimpleArrowRight;
			this.BorderColor = Color.Black;
			this.BorderWidth = 2;

			//this.BackColor = Color.YellowGreen;
			this.BackColor = Color.FromArgb(160, 60, 160);
			this.BackColor2 = Color.FromArgb(250, 200, 250);
			this.BackLinearGradientMode = LinearGradientMode.ForwardDiagonal;
			this.BackBrushMode = BackgroundBrushMode.LinearGradient;

			this.Size = new Size(100, 50);
			this.MinimumSize = new Size(100, 50);

			//this.Name = "exportSymbol" + GetCount(typeof(InterfaceSymbol));
			this.NameTextBox.AutoSize = false;
			this.NameTextBox.Bounds = this.ClientRectangle;
            this.NameTextBox.ReadOnly = true;
			this.Text = "Service";
			this.TextAlign = ContentAlignment.MiddleCenter;

			//
			// this.ContextMenuStrip
			//
			this.ContextMenuStrip = new ContextMenuStrip();
			this.ContextMenuStrip.Items.Add("Edit Capabilities...", null, new EventHandler(context_EditOperations));
			//this.ContextMenuStrip.Items.Add(new ToolStripSeparator());
			//this.ContextMenuStrip.Items.Add("Remove Capability", null, new EventHandler(context_Remove));

			_folder = null;
			_isCollapsed = false;
			_listOperations = new List<Operation>();
			_listConnectedInterfaces = new List<InterfaceSymbol>();

			_frmOps = null;

			this.EndUpdate();
		}
		#endregion

		#region Public Members

		#region Properties
		public List<Operation> Operations
		{
			get
			{
				if ( _listConnectedInterfaces.Count > 0 ) {
					List<Operation> list = new List<Operation>();
					foreach ( InterfaceSymbol symbol in _listConnectedInterfaces ) {
						list.AddRange(symbol.Operations);
					}
					return list;
				} else {
					return _listOperations;
				}
			}
		}
		public List<InterfaceSymbol> ConnectedInterfaces
		{
			get { return _listConnectedInterfaces; }
		}
		#endregion

		#region Events
		public event EventHandler OperationsChanged = null;
		#endregion

		#region Methods
		public void Expand()
		{
			_isCollapsed = false;
			this.MinimumSize = new Size(100, 50);
			this.Size = new Size(100, 50);
			this.NameTextBox.Visible = true;
			this.NameTextBox.AutoSize = false;
			this.NameTextBox.Bounds = this.ClientRectangle;
		}
		public void Collapse()
		{
			_isCollapsed = true;
			this.MinimumSize = new Size(25, 15);
			this.Size = new Size(25, 15);
			this.NameTextBox.Visible = false;
		}
		#endregion

		#region Overrides
		public override bool UseGrid
		{
			get
			{
				return false;//!_isCollapsed;
			}
		}
		public override bool NoClip
		{
			get
			{
				return true;
			}
		}
		public override bool CanMove
		{
			get
			{
				return false;
			}
		}
		public override bool CanResize
		{
			get
			{
				return false;
			}
		}

		public override object GetDragObject(Point location, MouseButtons button)
		{
			return this;
		}
		public override void DropObject(object obj, Point location, MouseButtons button)
		{
			if ( this.IsDropAllowed(obj, location, button) ) {
				if ( button == MouseButtons.Right ) {
					DesignerControl dctrl = obj as DesignerControl;
					if ( obj is ReferenceSymbol ) {
						this.DesignerViewControl.AddRoute((DesignerControl)obj, this);
					} else if ( obj is InterfaceSymbol ) {
						if ( dctrl.Parent is ServiceComponentSymbol )
							this.DesignerViewControl.AddRoute(this, (DesignerControl)obj);
						else if ( dctrl.Parent is ServiceModuleSymbol ) {
							if ( dctrl.Parent.Parent == this.Parent )
								this.DesignerViewControl.AddRoute(this, (DesignerControl)obj);
							else
								this.DesignerViewControl.AddRoute((DesignerControl)obj, this);
						} else if ( dctrl.Parent.Parent == this.Parent ) {
							this.DesignerViewControl.AddRoute(this, (DesignerControl)obj);
						}
					} else if ( obj is ExternalSymbol ) {
						this.DesignerViewControl.AddRoute((DesignerControl)obj, this);
					}
				}
			}
		}
		public override bool IsDropAllowed(object obj, Point location, MouseButtons button)
		{
			if ( button == MouseButtons.Right ) {
				DesignerControl dctrl = obj as DesignerControl;
				if ( obj is ReferenceSymbol ) {
					if ( dctrl.Parent is ServiceComponentSymbol )
						return ( this.Parent is ServiceComponentSymbol &&
								 dctrl.Parent.Parent == this.Parent.Parent );
					else if ( dctrl.Parent is ServiceModuleSymbol )
						return ( this.Parent is ServiceModuleSymbol &&
								 dctrl.Parent != this.Parent );
					else
						return false;
				} else if ( obj is InterfaceSymbol ) {
					if ( dctrl.Parent is ServiceComponentSymbol )
						return ( ( this.Parent is ServiceModuleSymbol || this.Parent is SOBASymbol ) &&
								 dctrl.Parent.Parent == this.Parent );
					else if ( dctrl.Parent is ServiceModuleSymbol ) {
						if ( this.Parent is ServiceComponentSymbol )
							return ( dctrl.Parent == this.Parent.Parent );
						else if ( this.Parent is ServiceModuleSymbol )
							return ( dctrl.Parent != this.Parent );
						else
							return false;
					} else
						return ( dctrl.Parent.Parent == this.Parent );
				} else {
					return ( obj is ExternalSymbol );
				}
			} else {
				return IsDropAllowed(obj.GetType(), location, button);
			}
		}
		public override bool IsDropAllowed(Type type, Point location, MouseButtons button)
		{
			return ( button == MouseButtons.Right &&
				( type == typeof(ReferenceSymbol) || type == typeof(ExternalSymbol) ||
				  type == typeof(InterfaceSymbol) ) );
		}

		public override Point GetRouteStart(RouteDockDirection dock, Route route)
		{
			Point pt = base.GetRouteStart(dock, route);
			return pt;
		}
		public override Point GetRouteEnd(RouteDockDirection dock, Route route)
		{
			Point pt = base.GetRouteEnd(dock, route);
			return pt;
		}

		public override bool CreateRouteStart(DesignerControl controlEnd,
			out IConnector connector, out LineCap cap, out CustomLineCap customcap,
			out RouteDockDirection dockStart, out RouteDockDirection dockEnd,
			out bool useStartConnectorAsRouteStart)
		{
			bool ok = base.CreateRouteStart(controlEnd, out connector, out cap, out customcap, out dockStart, out dockEnd, out useStartConnectorAsRouteStart);
			if ( controlEnd is InterfaceSymbol &&
					( controlEnd.Parent is ServiceComponentSymbol ||
					  ( controlEnd.Parent.Parent == this.Parent ) ) ) {
				addConnectedInterface((InterfaceSymbol)controlEnd);
			}
			//if ( _connectorInterface == null && (controlEnd is ImportSymbol || controlEnd is ExternalSymbol) ) {
			//    _connectorInterface = new InterfaceConnectorSymbol();
			//    _connectorInterface.Location = new Point(-(int)( _connectorInterface.Width / 2 ) - 5, (int)( this.ClientRectangle.Height / 2 ) - ( _connectorInterface.Height ) + 2);
			//    _connectorInterface.Anchor = System.Windows.Forms.AnchorStyles.Left;
			//    this.Controls.Add(_connectorInterface);
			//}
			if ( controlEnd is ReferenceSymbol ) {
				dockEnd = RouteDockDirection.Right;
				dockStart = RouteDockDirection.Left;
				//connector = _connectorInterface;
				//cap = LineCap.RoundAnchor;
				customcap = null;
			} else {
				dockEnd = RouteDockDirection.Left;
				dockStart = RouteDockDirection.Right;
				//cap = LineCap.RoundAnchor;
				customcap = null;
			}
			return ok;
		}
		public override bool CreateRouteEnd(DesignerControl controlStart,
			out IConnector connector, out LineCap cap, out CustomLineCap customcap,
			out RouteDockDirection dockStart, out RouteDockDirection dockEnd,
			out bool useEndConnectorAsRouteEnd)
		{
			bool ok = base.CreateRouteEnd(controlStart, out connector, out cap, out customcap, out dockStart, out dockEnd, out useEndConnectorAsRouteEnd);

			//if ( _connectorInterface == null ) {
			//    _connectorInterface = new InterfaceConnectorSymbol();
			//    _connectorInterface.Location = new Point(-(int)( _connectorInterface.Width / 2 ) - 5, (int)( this.ClientRectangle.Height / 2 ) - ( _connectorInterface.Height ) + 4);
			//    _connectorInterface.Anchor = System.Windows.Forms.AnchorStyles.Left;
			//    this.Controls.Add(_connectorInterface);
			//}
			//connector = _connectorInterface;
			if ( controlStart is ExternalSymbol ) {
				cap = LineCap.Custom;
				customcap = new AdjustableArrowCap(7.0f, 10.0f, false);
			} else {
				dockEnd = RouteDockDirection.Left;
				dockStart = RouteDockDirection.Right;
				//cap = LineCap.RoundAnchor;
				customcap = null;
			}
			return ok;
		}

		public override void ReadXml(System.Xml.XmlReader reader)
		{
			RepositoryService repSvc = (RepositoryService)this.GetService(typeof(RepositoryService));
			if ( repSvc == null )
				throw new NullReferenceException("RepositoryService not available.");

			System.ComponentModel.BooleanConverter bc = new System.ComponentModel.BooleanConverter();
			try {
				while ( reader.Read() ) {
					switch ( reader.Name ) {
						case "DesignerControl":
							if ( reader.NodeType == System.Xml.XmlNodeType.EndElement )
								return;
							break;
						case "IsCollapsed":
							bool.TryParse(reader.ReadString(), out _isCollapsed);
							if ( _isCollapsed )
								Collapse();
							break;
						case "GenericFolder":
							if ( reader.MoveToAttribute("id") && reader.ReadAttributeValue() )
								this.RepositoryItem = repSvc.GetItem(ItemType.GenericFolder, int.Parse(reader.Value), false);
							if ( reader.MoveToAttribute("isRef") && reader.ReadAttributeValue() )
								this.IsReference = (bool)bc.ConvertFromString(reader.Value);
							break;
						default:
							ReadStandardProperties(reader);
							break;
					}
				}
			} finally {
			}
		}
		public override void WriteXml(System.Xml.XmlWriter writer)
		{
			System.ComponentModel.BooleanConverter bc = new System.ComponentModel.BooleanConverter();
			WriteStandardProperties(writer);

			writer.WriteElementString("IsCollapsed", _isCollapsed.ToString());

			if ( _folder != null ) {
				writer.WriteStartElement("GenericFolder");
				writer.WriteAttributeString("id", _folder.ID.ToString());
				writer.WriteAttributeString("name", _folder.Name);
				writer.WriteAttributeString("isRef", bc.ConvertToString(this.IsReference));
				writer.WriteEndElement();
			}
		}

		public override object GetService(Type serviceType)
		{
			if ( _folder != null )
				return _folder.GetService(serviceType);
			else
				return base.GetService(serviceType);
		}

		public override void Paint(PaintEventArgs pe)
		{
			base.Paint(pe);
			Rectangle paintBound = this.GetPaintBounds();
			if ( this.Operations != null && this.Operations.Count > 1 ) {
				// diameter/radius of the exposed capability symbol
				int d = (int)( paintBound.Width * .2f ), r = (int)( d * .5f );
				Rectangle rect = new Rectangle(paintBound.X, paintBound.Y + (int)( paintBound.Height * .5f ) - r, d, d);
				rect.Inflate(-3, -3);
				pe.Graphics.DrawEllipse(this.BorderPen, rect);
			}
		}
		#endregion

		#endregion

		#region Protected Members

		#region Overrides
		protected override void CalculateBorder(int width, int height, ref GraphicsPath path)
		{
			//   _________ ____y1__
			//   \        \       ^
			//    \        \      |
			// O---)        )--y2 |h
			// |  /|       /|     |
			// | /_|______/_|__y3_v
			// | | |      | |
			//x1 x2 x3    x4 x5
			// |<-----w---->|
			int x1 = 0;
			int x2 = (int)( width * .2f );
			int x3 = x2 * 2;
			int x4 = (int)( width * .8f );
			int x5 = width;
			int y1 = 0;
			int y2 = (int)( height * .5f );
			int y3 = height;
			// diameter/radius of the exposed capability symbol
			int d = (int)( width * .2f ), r = (int)( d * .5f );
			path.AddPolygon(
				new Point[] {
					new Point(x2,y1),
					new Point(x4,y1),
					new Point(x5,y2),
					new Point(x4,y3),
					new Point(x2,y3),
					new Point(x3,y2)
				}
			);
			path.AddEllipse(x1, y2 - r, d, d);
			path.AddLine(x1 + d, y2, y3, y2);
		}
		protected override Rectangle CalculateClientArea()
		{
			//   _________ ____y1__
			//   \        \       ^
			//    \ cacaca \      |
			// O---)cacaca  )--y2 |h
			// |  /|cacaca /|     |
			// | /_|______/_|__y3_v
			// | | |      | |
			//x1 x2 x3    x4 x5
			// |<-----w---->|
			Rectangle rc = this.Bounds;
			//int x1 = 0;
			int x2 = (int)( rc.Width * .2f );
			int x3 = x2 * 2;
			int x4 = (int)( rc.Width * .8f );
			int x5 = rc.Width;
			//int y1 = 0;
			int y2 = (int)( rc.Height * .5f );
			int y3 = rc.Height;
			//int pad = 5;
			int x = rc.X + x3;
			int w = x4 - x3 + 5;
			int y = rc.Y + (int)( y3 * .25 );
			int h = rc.Height - (int)( y3 * .25 ) * 2;
			return new Rectangle(x, y, w, h);
		}
		protected override void OnVisibleChanged()
		{
			if ( !this._isCollapsed )
				base.OnVisibleChanged();
		}
		#endregion

		#endregion

		#region Private Members

		#region Variables
		//private InterfaceConnectorSymbol _connectorInterface;
		private bool _isCollapsed;
		private List<Operation> _listOperations;
		private List<InterfaceSymbol> _listConnectedInterfaces;
		private FormOperations _frmOps;
		#endregion

		#region Methods
		private void addConnectedInterface(InterfaceSymbol symbol)
		{
			if ( this.Mode == RepositoryModes.ITMode && this.Operations.Count > 0 ) {
				symbol.Operations.AddRange(this.Operations);
				_listOperations.Clear();
			}
			_listConnectedInterfaces.Add(symbol);
			_listOperations.AddRange(symbol.Operations);
			onOperationsChanged();
		}
		private void onOperationsChanged()
		{
			EventHandler tmp = this.OperationsChanged;
			if ( tmp != null )
				tmp(this, EventArgs.Empty);
		}
		#endregion

		#region Event Handlers
		private void context_EditOperations(object sender, EventArgs e)
		{
			if ( _frmOps == null ) {
				_frmOps = new FormOperations(_folder);
			} else {
				_frmOps.BringToFront();
				return;
			}
			if ( _listConnectedInterfaces.Count > 0 || this.Parent is CompositeReferenceSymbol ) {
				_frmOps.ReadOnly = true;
				this.Load(Global.Status.CurrentRepositoryId, Global.Status.CurrentDomainId);
			}
			_frmOps.FormClosed += new FormClosedEventHandler(frm_FormClosed);
			DockContent dc = this.DesignerViewControl.Parent as DockContent;
			IController ictrler = this.DesignerViewControl.DesignController as IController;
			if ( ictrler != null ) {
				ictrler.Closed += new EventHandler(ictrler_Closed);
			}
			if ( dc != null ) {
				Point loc = this.Parent.PointToDesignerView(this.Location);
				loc = this.DesignerViewControl.PointToScreen(loc);
				loc.X -= 50;
				loc.Y += this.Height + 20;
				_frmOps.Show(this.Operations, dc.DockPanel, loc);
			} else {
				_frmOps.Show(this.Operations);
			}
		}

		private void ictrler_Closed(object sender, EventArgs e)
		{
			if ( _frmOps != null ) {
				try {
					IController ictrler = sender as IController;
					if ( ictrler != null ) {
						ictrler.Closed -= new EventHandler(ictrler_Closed);
					}
					_frmOps.Close();
				} catch {
				} finally {
					_frmOps = null;
				}
			}
		}
		private void frm_FormClosed(object sender, FormClosedEventArgs e)
		{
			FormOperations frm = sender as FormOperations;
			if ( frm == null )
				return;
			if ( frm.DialogResult == DialogResult.OK && !frm.ReadOnly ) {
				_listOperations.Clear();
				_listOperations.AddRange(frm.Operations);
				if ( this.Parent is OrchestrationComponentSymbol ) {
					( (OrchestrationComponentSymbol)this.Parent ).ProcessOperation = null;
					foreach ( Operation op in _listOperations ) {
						if ( op.ProcessGuid != Guid.Empty ) {
							( (OrchestrationComponentSymbol)this.Parent ).ProcessOperation = op;
							break;
						}
					}
				}
				onOperationsChanged();
			}
			frm.FormClosed -= new FormClosedEventHandler(frm_FormClosed);
			_frmOps = null;
			if ( this.DesignerViewControl != null && this.DesignerViewControl.TopLevelControl != null ) {
				this.DesignerViewControl.TopLevelControl.BringToFront();
			}
		}

		private void context_Remove(object sender, EventArgs e)
		{
			if ( this.Delete(true) )
				this.Remove();
		}
		#endregion

		#endregion

		#region IRepositoryItemSymbol Members

		public bool SaveHierarchy
		{
			get { return true; }
		}

		private bool _isReference = false;
		public bool IsReference
		{
			get { return _isReference; }
			set { _isReference = value; }
		}

		public bool CanBeMainControl
		{
			get { return false; }
		}

		public OpenComposite.EII.Repository.IRepositoryItem RepositoryItem
		{
			get
			{
				return _folder;
			}
			set
			{
				_folder = value as Repository.GenericFolder;
				if ( _folder != null ) {
					_folder.Reload();
					if ( _folder.ID > 0 && _folder.Name != Resources.sNewGenericFolder )
						this.Text = _folder.Name;
					else
						_folder.Name = this.Text;
				}
			}
		}

		public void Load(int idRepository, int idDomain)
		{
			RepositoryService repSvc = (RepositoryService)this.GetService(typeof(RepositoryService));
			if ( repSvc == null )
				throw new NullReferenceException("RepositoryService not available.");

			if ( _folder != null ) {
				DataTable dt = Global.Data.GetRepositoryHierarchyChildRepositoryList(_folder, ItemType.Operation);
				_listOperations.Clear();
				foreach ( DataRow row in dt.Rows ) {
					Operation op = repSvc.GetItem(ItemType.Operation, row) as Operation;
					if ( op != null ) {
						_listOperations.Add(op);
						if ( op.ProcessGuid != Guid.Empty ) {
							if ( this.Parent is OrchestrationComponentSymbol )
								( (OrchestrationComponentSymbol)this.Parent ).ProcessOperation = op;
						}
					}
				}
			}
		}
		public bool Save(int idRepository, int idDomain)
		{
			if ( _folder == null ) {
				_folder = new GenericFolder(true);
				_folder.Name = this.Text;
			}

			bool ok = _folder.Save();
			if ( ok ) {
				Global.Data.DeleteRepositoryChildHierarchy(_folder);
				foreach ( Operation op in this.Operations ) {
					op.Save();
					Global.Data.AddRepositoryHierarchy(_folder, op, idRepository);
				}
			}
			return ok;
		}

		public bool Delete(bool bAsk)
		{
			if ( _folder == null )
				return true;

			return _folder.Delete(bAsk);
		}

		protected override void OnTextChanged(EventArgs e)
		{
			if ( _folder != null )
				_folder.Name = this.Text;

			base.OnTextChanged(e);
		}
		private Repository.GenericFolder _folder;


		#endregion
	}
}
